package com.gitee.wsl.struct.grammar.parser.combinator

import com.gitee.wsl.struct.grammar.parser.ParsingScope
import com.gitee.wsl.struct.grammar.parser.result.getOrElse
import com.gitee.wsl.struct.grammar.parser.token.AbstractToken
import com.gitee.wsl.struct.grammar.parser.token.AbstractWarpToken
import com.gitee.wsl.struct.grammar.parser.token.TokenMatch
import com.gitee.wsl.transform.validator.ValidatorWithTransform
import com.gitee.wsl.transform.validator.string.StringValidator
import com.gitee.wsl.transform.validator.validateWithResult
import timber.log.Timber

fun <P: AbstractToken> P.check(validatorWithTransform: ValidatorWithTransform<String?, String, *>.()-> ValidatorWithTransform<String?, String, *>): AbstractToken {
    val baseVal = ValidatorWithTransform.notNull<String,Exception> { Exception("error") }.validatorWithTransform()
    return CheckToken(this@check,baseVal)
}

class CheckToken<T: AbstractToken>(val token: T, val validatorWithTransform: ValidatorWithTransform<String?, String, *>): AbstractWarpToken(token)  {

    override fun match(input: CharSequence, fromIndex: Int): Int {
        var matchSize = token.match(input,fromIndex)
        if(matchSize > 0){
            validatorWithTransform(input.substring(fromIndex,fromIndex + matchSize)).onLeft {
                Timber.d("Tocken check error:$it")
                matchSize = 0
            }
        }
        return matchSize
    }

    override suspend fun ParsingScope.parse(): TokenMatch {
        val ret = tryParse(this@CheckToken).getOrElse { fail(it) }
        return ret
    }
}

fun <P: AbstractToken> P.check(validator: StringValidator): AbstractToken {
    return CheckStringValidatorToken(this@check,validator)
}

class CheckStringValidatorToken<T: AbstractToken>(val token: T, val validator: StringValidator): AbstractWarpToken(token)  {
    override fun match(input: CharSequence, fromIndex: Int): Int {
        var matchSize = token.match(input,fromIndex)
        if(matchSize > 0){
            val checkStr = input.substring(fromIndex,fromIndex + matchSize)
            validator.validateWithResult(checkStr).onFailure {
                Timber.d("Tocken check error:${it}")
                matchSize = 0
            }
        }
        return matchSize
    }

    override suspend fun ParsingScope.parse(): TokenMatch {
        val ret = tryParse(this@CheckStringValidatorToken).getOrElse { fail(it) }
        return ret
    }
}